package com.moody.calculator;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.moody.hibernate.domain.ReportData;
import com.moody.init.ReportModelInit;

/*
 * Copyright © Moody analytics   
 *
 * @Title: PublicVerify.java 
 * @Package： com.moody.calculator 
 * @author： Fuqiang Wang
 * @Description: 事业单位 报表校验   
 * @date： 2012-2-28 下午1:18:43
 * @Modified by: Fuqiang Wang 
 * @version V1.0   
 */

public class PublicVerify {
	private static final Logger log = LoggerFactory
			.getLogger(PublicVerify.class);
	private List<ReportData> reportDataList; // 某期报表的list
	private Map<String, Double> valueMap = new HashMap<String, Double>(); // 存储某期报表所有填写的数据项
	private Map<String,String> nameMap;
	private Map<String,String> checkMap;
	private List<String> resultList = new ArrayList<String>(); // 最终的返回结果

	public PublicVerify(List<ReportData> reportDataList) {
		this.reportDataList = reportDataList;
		nameMap = ReportModelInit.getInstance().getDisplayNameMap();
		checkMap = new HashMap<String,String>();
		
		initCheckMap();
	}

	public void loadData() {
		if (reportDataList != null) {
			for (ReportData rd : reportDataList) {
				valueMap.put(rd.getReportItemNo(), rd.getItemValue());
			}
		}
	}

	// 判断double类型是否为0
	public Boolean isZero(Double data) {
		if (data > 10E-6 || data < -(10E-6))
			return false;
		else
			return true;
	}

	public List<String> getResultList() {
		// 结果为空 重新检验
		if (resultList == null || resultList.size() == 0) {
			formVerify();
		}
		return resultList;
	}

	// 报表检验
	public void formVerify() {
		PublicVerify pv = new PublicVerify(reportDataList);
		pv.loadData();
		Method[] methods = PublicVerify.class.getDeclaredMethods();
		for (Method method : methods) {
			String name = method.getName();
			// 抽取所有以calculate的方法，表示是计算公式
			if (name.startsWith("verify")) {
				try {
					if (method.invoke(pv) != null)
						resultList.add(method.invoke(pv).toString());
				} catch (Exception e) {
					log.error("该项计算有误", e);
				}
			}
		}
		resultList.addAll(pv.checkBalance());
	}

	// 完整性检验
	public String verify001() {
		Boolean flag = true; // 是否完整
		for (ReportData rd : reportDataList) {
			if (rd.getItemValue() == null  && !rd.getReportItemNo().startsWith("PFR")) {
				flag = false;
				log.info(rd.getDisplayName());
			}
		}

		if (flag) {
			return null;
		} else {
			return "报表完整性检查:报表不完整";
		}
	}

	// 报表是否平衡
	public String verify002() {
		Double PBS030 = valueMap.get("PBS030");
		Double PBS060 = valueMap.get("PBS060");

		if(PBS030 != null && PBS060 != null){
			//资产 - 负债
			Double res = PBS030 - PBS060;
			BigDecimal bd = new BigDecimal(res);
			res = bd.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
			if(Math.abs(res) > 10E-6){
				return "资产负债表：资产部类 - 负债部类  = " + new DecimalFormat("###,##0.00").format(res);
			}
		}
		
		return null;
		
	}

	// 资产合计<0
	public String verify003() {
		Double PBS017 = valueMap.get("PBS017");

		if (PBS017 == null || PBS017 < 0)
			return "资产合计缺失或者资产合计 < 0 或为空值";
		else
			return null;
	}

	// 支出合计<0
	public String verify004() {
		Double PBS029 = valueMap.get("PBS029");

		if (PBS029 == null || PBS029 < 0)
			return "支出合计缺失或者支出合计 < 0 或为空值";
		else
			return null;
	}

	// 负债合计<0
	public String verify005() {
		Double PBS041 = valueMap.get("PBS041");

		if (PBS041 == null || PBS041 < 0)
			return "负债合计缺失或者负债合计 < 0 或为空值";
		else
			return null;
	}

	// 净资产合计<0
	public String verify006() {
		Double PBS050 = valueMap.get("PBS050");

		if (PBS050 == null || PBS050 < 0)
			return "净资产合计缺失或者净资产合计 < 0 或为空值";
		else
			return null;
	}

	// 收入合计<0
	public String verify007() {
		Double PBS059 = valueMap.get("PBS059");

		if (PBS059 == null || PBS059 < 0)
			return "收入合计缺失或者收入合计 < 0 或为空值";
		else
			return null;
	}

//	// 资产部类总计=资产合计+支出合计;
//	public String verify008() {
//		Double PBS030 = valueMap.get("PBS030");
//		Double PBS017 = valueMap.get("PBS017");
//		Double PBS029 = valueMap.get("PBS029");
//
//		if (PBS030 != null && PBS017 != null && PBS029 != null
//				&& isZero(PBS030 - PBS017 - PBS029))
//			return null;
//		else
//			return "资产部类总计 ≠ 资产合计 + 支出合计";
//	}

//	// 负债部类总计 ≠ 负债合计 + 净资产合计 + 收入合计;
//	public String verify009() {
//		Double PBS060 = valueMap.get("PBS060");
//		Double PBS041 = valueMap.get("PBS041");
//		Double PBS050 = valueMap.get("PBS050");
//		Double PBS059 = valueMap.get("PBS059");
//
//		if (PBS060 != null && PBS041 != null && PBS050 != null
//				&& PBS059 != null && isZero(PBS060 - PBS041 - PBS050 - PBS059))
//			return null;
//		else
//			return "负债部类总计  ≠ 负债合计 + 净资产合计 + 收入合计";
//	}

	/*
	 * 收入支出表
	 */

	// 预算外资金收入不能大于事业收入
	public String verify010() {
		Double PIS006 = valueMap.get("PIS006");
		Double PIS005 = valueMap.get("PIS005");

		if (PIS005 != null && PIS006 != null && PIS006 <= PIS005)
			return null;
		else
			return "预算外资金收入 > 事业收入  （或其中之一为空值）";
	}

	// 其中：财政补助支出+预算外资金支出<=事业支出
	public String verify011() {
		Double PIS019 = valueMap.get("PIS019");
		Double PIS020 = valueMap.get("PIS020");
		Double PIS018 = valueMap.get("PIS018");

		if (PIS019 != null && PIS020 != null && PIS018 != null
				&& (PIS019 + PIS020) <= PIS018)
			return null;
		else
			return "政补助支出 + 预算外资金支出 > 事业支出  （或其中之一为空值）";
	}

	
	public List<String> checkBalance(){
		DecimalFormat df = new DecimalFormat("###,##0.00");
		Set<String> keySet = checkMap.keySet();
		for(String sumKey :keySet){
			if(!valueMap.containsKey(sumKey)) continue;
//			log.info("总和：" + valueMap.get(sumKey) +"("+sumKey+")");
			String[] itemArray = checkMap.get(sumKey).split(",");
			double res = 0;
			for(String itemKey : itemArray){
				double value = 0;
				if(itemKey.substring(0, 1).equals("-")) value =  valueMap.get(itemKey.substring(1)) * -1;
				else value = valueMap.get(itemKey);
				res += value; 
//				log.info("———— " + value + "("+itemKey+")");
			}
			
			
			res = valueMap.get(sumKey) - res;
			
			BigDecimal bd = new BigDecimal(res);
			res = bd.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
			
			if(Math.abs(res) > 10E-6){
//				log.info("————差额： " + res);
				String itemList = "";
				if(itemArray.length == 1){
					itemList = nameMap.get(itemArray[0]);
				}
				else{
					itemList = "(";
					for(String itemKey : itemArray){
						if(itemKey.substring(0, 1).equals("-")) {
							if(itemList.length() > 1) itemList += " -";
							itemList += " " + nameMap.get(itemKey.substring(1));
						}
						else {
							if(itemList.length() > 1) itemList += " +";
							itemList += " " + nameMap.get(itemKey);
						}
					}
					itemList += ")";
				}
				
				String title = null;
				if(sumKey.contains("BS")) title = "资产负债表：";
				else if(sumKey.contains("EIS")) title = "利润表：";
				else if(sumKey.contains("PIS")) title = "收入支出表：";
				else if(sumKey.contains("FIS")) title = "损益表：";
				else if(sumKey.contains("CF")) title = "现金流量表：";
				resultList.add(title + nameMap.get(sumKey) +" - " + itemList +" = " + df.format(res));
				
			}
		}
		return resultList;
	}
	
	private void initCheckMap(){

		checkMap.put("PBS017", "PBS004,PBS005,PBS011,PBS006,PBS012,PBS013,PBS008,PBS009,PBS014,PBS015,PBS016");
		checkMap.put("PBS029", "PBS019,PBS020,PBS021,PBS022,PBS023,PBS024,PBS025,PBS026,PBS027,PBS028");
		checkMap.put("PBS030", "PBS017,PBS029");
		checkMap.put("PBS041", "PBS032,PBS033,PBS034,PBS036,PBS037,PBS038,PBS039,PBS040");
		checkMap.put("PBS050", "PBS043,PBS044,PBS045,PBS046,PBS047,PBS048,PBS049");
		checkMap.put("PBS059", "PBS052,PBS053,PBS054,PBS055,PBS056,PBS057,PBS058");
		checkMap.put("PBS060", "PBS041,PBS050,PBS059");

		checkMap.put("PIS008", "PIS002,PIS003,PIS004,PIS005,PIS006,PIS007");
		checkMap.put("PIS013", "PIS008,PIS010,PIS012");
		checkMap.put("PIS023", "PIS015,PIS016,PIS017,PIS018,PIS021,PIS022");
		checkMap.put("PIS026", "PIS024,PIS025");
		checkMap.put("PIS029", "PIS027,PIS028");
		checkMap.put("PIS030", "PIS023,PIS026,PIS029");
		checkMap.put("PIS032", "PIS008,-PIS023");
		checkMap.put("PIS035", "PIS010,-PIS026");
		checkMap.put("PIS037", "PIS038,PIS039,PIS040,PIS041");
		
		
	}
}
